// 7、Vue 3.0中对外暴露了包含computed方法
// 效果是传入一个函数，返回一个默认不可手动修改的 ref 对象。
// 实现computed函数，要求computed在依赖数据变更的时候逻辑的计算结果也是响应式的
// 注意这个computed函数属于Composition API，与options选项的computed并不是一个东西


import { log } from "./shared";

// ----->来自模块2的代码
const targetMap = new WeakMap(); // 全局映射：响应式对象--->属性依赖集合
function trigger(targetMap:TargetMap, target:any, key:any) {
  const depMap:DepMap|undefined = targetMap.get(target);
  if (!depMap) return;
  const dep:Dep|undefined = depMap.get(key);
  if (dep) {
    dep.forEach((effect) => {
      effect();
    });
  }
}




// ----->来自模块4的代码
const handler = {
  get(target: any, key: string | number, receiver: any) {
    let res: any = Reflect.get(target, key, receiver);
    track(targetMap, target, key); // 注意：在这里收集追踪依赖！！
    return res;
  },
  set(target: any, key: string | number, value: any, receiver: any) {
    let previousValue: any = target[key]; // 旧值
    let res: boolean = Reflect.set(target, key, value, receiver); // 注意先后顺序，先反射再检测值是否需要触发更新
    if (previousValue !== value) {
      trigger(targetMap, target, key);
    }
    return res;
  },
};
function reactive(target: any) {
  return new Proxy(target, handler);
}




// ----->来自模块5的代码
let activeEffect: RunTimeFunction = null; // 用来记录runtime的函数，Vue 2中也运用过这个标记技巧
function effect(eff: Function) {
  activeEffect = eff;
  activeEffect();
  activeEffect = null;
}
function track(targetMap: TargetMap, target: any, key: string | number) {
  if (activeEffect) {
    let depMap: DepMap | undefined = targetMap.get(target);
    if (!depMap) {
      depMap = new Map();
      targetMap.set(target, depMap);
    }
    let dep: Dep | undefined = depMap.get(key);
    if (!dep) {
      dep = new Set();
      depMap.set(key, dep);
    }
    dep.add(activeEffect);
  }
}




// ----->来自模块6的代码
function ref<T>(primitiveValue: RefValue<T>) {
  const refObj: Ref<T> = {
    get value() {
      track(targetMap, refObj, "value"); // 收集该对象的依赖
      return primitiveValue;
    },
    set value(newValue) {
      if (primitiveValue !== newValue) {
        primitiveValue = newValue;
        trigger(targetMap, refObj, "value"); // 触发该属性的依赖
      }
    },
  };
  return refObj;
}




// ----->下面开始的是模块7的代码

// computed函数，内核是基于ref类型实现，它的value值是响应式的，本身也是ref类型
function computed<T>(logic:ComputedLogic<T>) {
  let result: any = 0;
  effect(() => ( result = logic())); // 在effect中跑一边计算逻辑并收集依赖，相当于监听了因变量
  return ref<T>(result as RefValue<T>); // 返回包装的计算结果。并且它的value是响应式的
}




// 测试用例 7
let stringObj = reactive({
  content: "hello Vue 2.0 !",
}); // 这个stringObj是响应式对象
let reverseString = computed(() =>
  stringObj.content.split("").reverse().join("")
); // reverseString是一个ref类型，它的value值基于computed逻辑也是响应式的
let amazingString = computed(() => stringObj.content + "!!!!"); // 同reverseString


// 以下的combineString依赖于两个计算逻辑reverseString和amazingString
let combineString = computed(() => amazingString.value + reverseString.value);
log(reverseString.value, amazingString.value, 1);
log(combineString.value, 2);
stringObj.content = "hello Vue 3.0 !";
log(reverseString.value, amazingString.value, 3);
log(combineString.value, 4);
